{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "3CF2edFAI4Uj"
   },
   "source": [
    "<a href=\"https://colab.research.google.com/github/jeffheaton/app_deep_learning/blob/main/t81_558_class_11_3_tokenizers.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "RvbM-RwHI4Ul"
   },
   "source": [
    "# T81-558: Applications of Deep Neural Networks\n",
    "**Module 11: Natural Language Processing with Hugging Face**\n",
    "* Instructor: [Jeff Heaton](https://sites.wustl.edu/jeffheaton/), McKelvey School of Engineering, [Washington University in St. Louis](https://engineering.wustl.edu/Programs/Pages/default.aspx)\n",
    "* For more information visit the [class website](https://sites.wustl.edu/jeffheaton/t81-558/)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "5dE7A-0aI4Ul"
   },
   "source": [
    "# Module 11 Material\n",
    "\n",
    "* Part 11.1: Introduction to Hugging Face [[Video]](https://www.youtube.com/watch?v=PzuL84ksRuE&list=PLjy4p-07OYzuy_lHcRW8lPTLPTTOmUpmi) [[Notebook]](t81_558_class_11_1_hf.ipynb)\n",
    "* Part 11.2: Hugging Face in Python [[Video]](https://www.youtube.com/watch?v=tkGIF4CFoV4&list=PLjy4p-07OYzuy_lHcRW8lPTLPTTOmUpmi) [[Notebook]](t81_558_class_11_2_py_huggingface.ipynb)\n",
    "* **Part 11.3: Hugging Face Tokenizers** [[Video]](https://www.youtube.com/watch?v=Cz2nvfK28eI&list=PLjy4p-07OYzuy_lHcRW8lPTLPTTOmUpmi) [[Notebook]](t81_558_class_11_3_tokenizers.ipynb)\n",
    "* Part 11.4: Hugging Face Datasets [[Video]](https://www.youtube.com/watch?v=yLlCZLzE2XU&list=PLjy4p-07OYzuy_lHcRW8lPTLPTTOmUpmi) [[Notebook]](t81_558_class_11_4_hf_datasets.ipynb)\n",
    "* Part 11.5: Training Hugging Face Models [[Video]](https://www.youtube.com/watch?v=7YZOik5S3vs&list=PLjy4p-07OYzuy_lHcRW8lPTLPTTOmUpmi) [[Notebook]](t81_558_class_11_5_hf_train.ipynb)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9Z4A091yI4Um"
   },
   "source": [
    "# Google CoLab Instructions\n",
    "\n",
    "The following code checks if Google CoLab is running."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "RJmzbge9I4Um",
    "outputId": "4685a76c-cc37-490a-d589-db16eb6e9c4c"
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    from google.colab import drive\n",
    "    COLAB = True\n",
    "    print(\"Note: using Google CoLab\")\n",
    "except:\n",
    "    print(\"Note: not using Google CoLab\")\n",
    "    COLAB = False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "vdNN6e45I4Un"
   },
   "source": [
    "# Part 11.3: Hugging Face Tokenizers\n",
    "\n",
    "Tokenization is the task of chopping it up into pieces, called tokens, perhaps at the same time throwing away certain characters, such as punctuation. Consider how the program might break up the following sentences into words.\n",
    "\n",
    "* This is a test.\n",
    "* Ok, but what about this?\n",
    "* Is U.S.A. the same as USA.?\n",
    "* What is the best data-set to use?\n",
    "* I think I will do this-no wait; I will do that.\n",
    "\n",
    "The hugging face includes tokenizers that can break these sentences into words and subwords. Because English, and some other languages, are made up of common word parts, we tokenize subwords. For example, a gerund word, such as \"sleeping,\" will be tokenized into \"sleep\" and \"##ing\".\n",
    "\n",
    "We begin by installing Hugging Face if needed.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "3jGET2abMjcl",
    "outputId": "35b8be0f-bc7e-42d0-f177-ee097d4a076c"
   },
   "outputs": [],
   "source": [
    "# HIDE OUTPUT\n",
    "!pip install transformers\n",
    "!pip install transformers[sentencepiece]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Wa1ncodn8y0r"
   },
   "source": [
    "First, we create a Hugging Face tokenizer. There are several different tokenizers available from the Hugging Face hub. For this example, we will make use of the following tokenizer:\n",
    "\n",
    "* distilbert-base-uncased\n",
    "\n",
    "This tokenizer is based on BERT and assumes case-insensitive English text."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "kSGtW0E7xcK9"
   },
   "outputs": [],
   "source": [
    "from transformers import AutoTokenizer\n",
    "model = \"distilbert-base-uncased\"\n",
    "tokenizer = AutoTokenizer.from_pretrained(model)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "YofjyJw59U2x"
   },
   "source": [
    "We can now tokenize a sample sentence."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "NVCmyao2zLQ3",
    "outputId": "6b33031a-8667-4431-aae2-26595195d69d"
   },
   "outputs": [],
   "source": [
    "encoded = tokenizer('Tokenizing text is easy.')\n",
    "print(encoded)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "4QgmlpyezhMy"
   },
   "source": [
    "The result of this tokenization contains two elements:\n",
    "* input_ids - The individual subword indexes, each index uniquely identifies a subword.\n",
    "* attention_mask - Which values in *input_ids* are meaningful and not  padding.\n",
    "This sentence had no padding, so all elements have an attention mask of \"1\". Later, we will request the output to be of a fixed length, introducing padding, which always has an attention mask of \"0\". Though each tokenizer can be implemented differently, the attention mask of a tokenizer is generally either \"0\" or \"1\". \n",
    "\n",
    "Due to subwords and special tokens, the number of tokens may not match the number of words in the source string. We can see the meanings of the individual tokens by converting these IDs back to strings."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Ww3XPc-i2Y6c",
    "outputId": "6179b416-61cd-4142-fa15-ae2296e9eab7"
   },
   "outputs": [],
   "source": [
    "tokenizer.convert_ids_to_tokens(encoded.input_ids)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "7KM7VRJECoGU"
   },
   "source": [
    "As you can see, there are two special tokens placed at the beginning and end of each sequence. We will soon see how we can include or exclude these special tokens. These special tokens can vary per tokenizer; however, [CLS] begins a sequence for this tokenizer, and [SEP] ends a sequence. You will also see that the gerund \"tokening\" is broken into \"token\" and \"*ing\".\n",
    "\n",
    "For this tokenizer, the special tokens occur between 100 and 103. Most Hugging Face tokenizers use this approximate range for special tokens. The value zero (0) typically represents padding. We can display all special tokens with this command.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "EtQiOmSl2rXt",
    "outputId": "6f5f2aef-d718-4675-d0a5-9c6c9d960c87"
   },
   "outputs": [],
   "source": [
    "tokenizer.convert_ids_to_tokens([0, 100, 101, 102, 103])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "1nQ-r6bz3ESN"
   },
   "source": [
    "This tokenizer supports these common tokens:\n",
    "\n",
    "* \\[CLS\\] - Sequence beginning.\n",
    "* \\[SEP\\] - Sequence end.\n",
    "* \\[PAD\\] - Padding.\n",
    "* \\[UNK\\] - Unknown token.\n",
    "* \\[MASK\\] - Mask out tokens for a neural network to predict. Not used in this book, see [MLM paper](https://arxiv.org/abs/2109.01819). \n",
    "\n",
    "It is also possible to tokenize lists of sequences. We can pad and truncate sequences to achieve a standard length by tokenizing many sequences at once.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "TI4RZXhc4v9k",
    "outputId": "2ae7f2f9-3d8a-421e-c9b9-4dd933817cd3"
   },
   "outputs": [],
   "source": [
    "text = [\n",
    "    \"This movie was great!\",\n",
    "    \"I hated this move, waste of time!\",\n",
    "    \"Epic?\"\n",
    "]\n",
    "\n",
    "encoded = tokenizer(text, padding=True, add_special_tokens=True)\n",
    "\n",
    "print(\"**Input IDs**\")\n",
    "for a in encoded.input_ids:\n",
    "    print(a)\n",
    "\n",
    "print(\"**Attention Mask**\")\n",
    "for a in encoded.attention_mask:\n",
    "    print(a)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "1rIF8TEEF9C-"
   },
   "source": [
    "Notice the **input_id**'s for the three movie review text sequences. Each of these sequences begins with 101 and we pad with zeros. Just before the padding, each group of IDs ends with 102. The attention masks also have zeros for each of the padding entries. \n",
    "\n",
    "We used two parameters to the tokenizer to control the tokenization process. Some other useful [parameters](https://huggingface.co/docs/transformers/main_classes/tokenizer) include:\n",
    "\n",
    "* add_special_tokens (defaults to True) Whether or not to encode the sequences with the special tokens relative to their model.\n",
    "* padding (defaults to False) Activates and controls truncation.\n",
    "* max_length (optional) Controls the maximum length to use by one of the truncation/padding parameters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "colab": {
   "collapsed_sections": [],
   "name": "t81_558_class_11_02_tokenizers.ipynb",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3.9 (torch)",
   "language": "python",
   "name": "pytorch"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
